<?php
/*********************************************
  Dragonfly CMS, Copyright (c) 2004 by CPGNuke Dev Team
  http://dragonflycms.org
  Released under GNU GPL version 2 or any later version

  $Source$
  $Revision$
  $Author$
  $Date$
**********************************************/

abstract class CSS
{

	protected static $toClientPattern = array('#^i:([a-z0-9_]+)$#', '#^t:([a-z0-9_]+):([a-z0-9_]+)$#i', '#^m:([a-z0-9_]+):([a-z0-9_]+)$#i');
	protected static $toClientReplace = array('includes/css/$1.css', 'themes/$1/style/$2.css', 'modules/$1/style/$2.css' );

	protected static $toTplPattern = array('#^includes/css/([a-z0-9_]+)\.css$#', '#^themes/([a-z0-9_]+)/style/([a-z0-9_]+)\.css$#i', '#^module/([a-z0-9_]+)/style/([a-z0-9_]+)\.css$#i');
	protected static $toTplReplace = array('i:$1', 't:$1:$2', 'm:$1:$2');

	private static $mediaTypes = array(
		'all',          # Includes all media types listed below
		'aural',        # Speech and sound synthesizers
		'braille',      # Braille tactile feedback devices
		'embossed',     # Paged braille printers
		'handheld',     # Small or handheld devices
		'inline',       // try this to fix the inline issue?
		'print',        # Printing
		'projection',   # Projected presentations, eg slides
		'screen',       # Computer screens
		'tty',          # Fixed-pitch character grid, like teletypes and terminals
		'tv'            # Television-type devices
	);

	private static $files = array();
	private static $inline = array();
	private static $mtime = 0;
	private static $canAdd = true;
	public static $theme;

	final public static function add($file, $media='screen')
	{
		$media = trim($media);
		if (self::$canAdd && preg_match('#^[a-z0-9:\(\)\,\- ]+$#i', $media) && self::filter($file, 'toTpl') && is_file(BASEDIR .$file)) {
			self::$files[$media][] = preg_replace(self::$toTplPattern, self::$toTplReplace, $file);
		}
	}

	final public static function inline($str, $media='screen')
	{
		self::$inline[$media][] = $str;
	}

	final public static function flushToTpl()
	{
		foreach (self::$files as $key => $val) {
			self::$files[$key] = array_values(array_unique($val));
		}
		$return = '';
		self::add('themes/'.self::$theme.'/style/custom.css');
		foreach (self::$files as $key => $val) {
			$return .= '<link rel="stylesheet" type="text/css" media="' .$key .'" href="?css=' .implode(';', $val) ."\" />".DF_EOL;
		}
		foreach (self::$inline as $key => $val) {
			$return .= '<style type="text/css" media="' .$key .'">';
			while ($str = array_shift($val)) {
				$return .= self::minify($str) .DF_EOL;
			}
			$return .= '</style>' .DF_EOL;
		}
		self::$files = array();
		return $return;
	}

	final public static function request()
	{
		self::$canAdd = false;
		if (!preg_match('#^[a-z0-9_\-;:]+$#iD', $_GET['css'])) return false;
		$items = explode(';', $_GET['css']);
		for ($i=0, $c=count($items); $i<$c; ++$i) {
			if (self::filter($items[$i], 'toClient')) {
				$file = BASEDIR .preg_replace(self::$toClientPattern, self::$toClientReplace, $items[$i]);
				if (is_file($file)) {
					self::$files[] = $file;
					self::$mtime = max(self::$mtime, filemtime($file));
				} else {
					trigger_error($items[$i] .' could not be found', E_USER_WARNING);
				}
			}
		}
		self::$files = array_values(array_unique(self::$files));
		return !empty(self::$files);
	}

	final public static function minify($str)
	{
		if (DF_MODE_DEVELOPER) return $str;
		$str = trim(preg_replace('#\s\s+#', ' ', $str));
		$str = preg_replace('#/\*.*?\*/#s', '', $str);
		$str = preg_replace('#\s*[^{}]+{\s*}\s*#', '', $str);
		$str = preg_replace('#\s*([{},;:])\s*#', '$1', $str);
		$str = str_replace(';}', '}', $str);
		return $str;
	}

	final public static function flushToClient()
	{
		$ETag = md5(implode(';', self::$files).self::$mtime);
		$gzip = GZIP_OUT ? '.gz' : '';
		$cachedFile = CACHE_PATH .'css#' .$ETag;
		$life_time = (DF_MODE_DEVELOPER ? 0 : DF_HTTP_CACHE_EXPIRE);
		if ('1.1' > Dragonfly_Net_Http::$protocolVersion) {
			header('Cache-Control: public, s-maxage=' .$life_time);
		} else {
			header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + $life_time));
		}
		header('Content-Type: text/css; charset=utf-8');
		if (!CPG_DEBUG && is_file($cachedFile .$gzip) && self::$mtime < filemtime($cachedFile .$gzip)) {
			if ($gzip) {
				header('Vary: Accept-Encoding');
				header('Content-Encoding: gzip');
			}
			header('Content-Length:' .filesize($cachedFile .$gzip));
			if ($status = Dragonfly_Net_Http::entityCache($ETag, self::$mtime)) {
				Dragonfly_Net_Http::headersFlush($status);
			} else if ('GET' === $_SERVER['REQUEST_METHOD']) {
				readfile($cachedFile .$gzip);
			}
			exit;
		}
		$buffer = '';
		foreach (self::$files as $i => $file ) {
			$buffer .= file_get_contents($file);
		}
		$buffer = preg_replace('#((url\(|src=)["\']?)\.\.\/images/#', '$1' .DF_STATIC_DOMAIN .'themes/' .self::$theme .'/images/', $buffer);
		$buffer = preg_replace('#((url\(|src=)["\']?)/images/#', '$1' .DF_STATIC_DOMAIN .'images/', $buffer);
		if (!CPG_DEBUG) { $buffer = self::minify($buffer); }
		if (GZIPSUPPORT && $gz = gzopen($cachedFile .'.gz','w9')) {
			gzwrite($gz, $buffer);
			gzclose($gz);
		}
		file_put_contents($cachedFile, $buffer);
		//trigger_error('here', E_USER_WARNING);
		if (!CPG_DEBUG && is_file($cachedFile .$gzip) || !$gzip) {
			if ($gzip) header('Content-Encoding: gzip');
			header('Content-Length:' .filesize($cachedFile .$gzip));
			if ('GET' === $_SERVER['REQUEST_METHOD']) exit(readfile($cachedFile .$gzip));
		} else {
			ob_start('ob_gzhandler');
			if ('GET' === $_SERVER['REQUEST_METHOD']) exit($buffer);
		}
		exit;
	}

	private static function filter($str, $mode)
	{
		switch ($mode) {
			case 'toTpl':
				$pattern = self::$toTplPattern;
			break;
			case 'toClient':
				$pattern = self::$toClientPattern;
			break;
			default: return;
		}
		for ($i=0, $c=count($pattern); $i<$c; ++$i) {
			if (1 === preg_match($pattern[$i], $str, $match)) {
				if (!self::$theme && isset($match[2])) self::$theme = $match[1];
				return true;
			}
		}
		return false;
	}

}